﻿using Basic.FlowApplication.Model;
using Basic.FlowApplication.Model.AuditLog;
using Basic.FlowModel.AuditLog;
using Basic.FlowModel.AuditLogItem;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Application.Model;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.QueryInter.Model;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.Extend
{
    internal static class LinqHelper
    {
        public static long[] CheckIsToVoid ( this AuditFlowBody flow, FlowNode end, long[] nodeId )
        {
            return nodeId.FindAll(a => _CheckIsToVoid(flow, end, flow.Nodes[a]));
        }
        public static bool CheckIsNoPass ( this FlowAuditLogState log, FlowNode node, long endId )
        {
            if ( node.IntoCondition == FlowNodeIntoCondition.全部通过 )
            {
                return true;
            }
            else if ( node.IntoCondition == FlowNodeIntoCondition.指定节点通过 && node.IntoWaitNodeId == endId )
            {
                return true;
            }
            int num = node.PrevNodeId.Count(a => log.CurNodeState[a] == FlowNodeAuditStatus.审核未通过) + 1;
            return num > ( node.PrevNodeId.Length - node.IntoMinPassNum.Value );
        }
        private static bool _CheckIsToVoid ( AuditFlowBody flow, FlowNode end, FlowNode node )
        {
            if ( node.ToNodeId.Contains(end.Id) )
            {
                return true;
            }
            else if ( node.ToNodeId.Length == 1 )
            {
                FlowNode to = flow.Nodes[node.ToNodeId[0]];
                if ( to.NodeType == FlowNodeType.结束节点 || to.NodeLvl > end.NodeLvl || to.PrevNodeId.Length > 1 )
                {
                    return false;
                }
                return _CheckIsToVoid(flow, end, to);
            }
            else
            {
                FlowNode to = null;
                foreach ( long i in node.ToNodeId )
                {
                    FlowNode t = flow.Nodes[i];
                    if ( t.NodeType == FlowNodeType.子流程 )
                    {
                        continue;
                    }
                    else if ( to != null )
                    {
                        return false;
                    }
                    to = t;
                }
                if ( to == null ||
                    to.NodeType == FlowNodeType.结束节点 ||
                    to.NodeLvl > end.NodeLvl ||
                    to.PrevNodeId.Length > 1 )
                {
                    return false;
                }
                return _CheckIsToVoid(flow, end, to);
            }
        }
        public static Tuple<FlowNode, long> GetBranchNode ( this AuditFlowBody flow, FlowNode node )
        {
            FlowNode to = null;
            if ( node.ToNodeId.Length > 1 )
            {
                foreach ( long i in node.ToNodeId )
                {
                    FlowNode t = flow.Nodes[i];
                    if ( t.NodeType == FlowNodeType.子流程 )
                    {
                        continue;
                    }
                    else if ( to != null )
                    {
                        return null;
                    }
                    to = t;
                }
            }
            else
            {
                to = flow.Nodes[node.ToNodeId[0]];
            }
            if ( to.NodeType == FlowNodeType.结束节点 )
            {
                return null;
            }
            else if ( to.PrevNodeId.Length > 1 )
            {
                return new Tuple<FlowNode, long>(to, node.Id);
            }
            return flow.GetBranchNode(node);
        }

        public static void CheckAuditItem ( this AfootAuditLogItem item, AuditRes result, FlowAuditItemStatus status = FlowAuditItemStatus.审核进行中 )
        {
            if ( item.AuditState != status )
            {
                throw new ErrorException("flow.audit.status.error");
            }
            else if ( item.EmpId != result.AuditEmpId )
            {
                throw new ErrorException("flow.audit.emp.error");
            }
        }
        public static void CheckAuditItem ( this AfootAuditLogItem item, AuditRes result, FlowAuditItemStatus[] status )
        {
            if ( !status.Contains(item.AuditState) )
            {
                throw new ErrorException("flow.audit.status.error");
            }
            else if ( item.EmpId != result.AuditEmpId )
            {
                throw new ErrorException("flow.audit.emp.error");
            }
        }
        public static string FormatString ( this FormVal val )
        {
            if ( val.IsNull )
            {
                return null;
            }
            else if ( val.DataType == FormRecordDataType.String )
            {
                if ( val.FuncType == DataFuncType.选项值 && val.Items != null )
                {
                    return val.Items.GetValueOrDefault(val.StrVal);
                }
                return val.StrVal;
            }
            else if ( val.DataType == FormRecordDataType.Date )
            {
                return val.LongVal.Value.ToDateTime().ToString("yyyy-MM-dd");
            }
            else if ( val.DataType == FormRecordDataType.DateTime )
            {
                return val.LongVal.Value.ToDateTime().ToString("yyyy-MM-dd HH:mm");
            }
            else if ( val.DataType == FormRecordDataType.Bool )
            {
                return val.BoolVal.Value ? val.ActivateText : val.InactiveText;
            }
            else if ( val.DataType == FormRecordDataType.ListItem )
            {
                return _GetValueText(val);
            }
            else if ( val.DataType == FormRecordDataType.Number )
            {
                if ( val.NumStep.HasValue )
                {
                    string format = "N" + val.NumStep.Value.ToString();
                    return val.NumVal.Value.ToString(format);
                }
                return val.NumVal.Value.ToString("N2");
            }
            else if ( val.DataType == FormRecordDataType.Array )
            {
                if ( val.FuncType == DataFuncType.选项值 && val.Items != null )
                {
                    string[] vals = val.Vals.ConvertAll(c => val.Items.GetValueOrDefault(c));
                    return string.Join(',', vals);
                }
                return string.Join(',', val.Vals);
            }
            else
            {
                return val.LongVal.Value.ToString();
            }
        }
        private static string _GetValueText ( FormVal val )
        {
            FormListItem item = val.ListItem;
            if ( item.DataType == FormRecordDataType.Bool )
            {
                return item.BoolVal.Join(',', a => a.GetValueOrDefault(false) ? val.ActivateText : val.InactiveText);
            }
            else if ( item.DataType == FormRecordDataType.String )
            {
                if ( val.FuncType == DataFuncType.选项值 && val.Items != null )
                {
                    string[] vals = item.StrVal.ConvertAll(c => val.Items.GetValueOrDefault(c));
                    return string.Join(',', vals);
                }
                return item.StrVal.Join(',');
            }
            else if ( item.DataType == FormRecordDataType.Number )
            {
                if ( val.NumStep.HasValue )
                {
                    string format = "N" + val.NumStep.Value.ToString();
                    return item.NumVal.Join(',', a => a.HasValue ? a.Value.ToString(format) : string.Empty);
                }
                return item.NumVal.Join(',', a => a.HasValue ? a.Value.ToString() : string.Empty);
            }
            else if ( item.DataType == FormRecordDataType.Long || item.DataType == FormRecordDataType.Time )
            {
                return item.LongVal.Join(',', a => a.HasValue ? a.Value.ToString() : string.Empty);
            }
            else if ( item.DataType == FormRecordDataType.Date )
            {
                return item.LongVal.Join(',', a => a.HasValue ? a.Value.ToDateTime().ToString("yyyy-MM-dd") : string.Empty);
            }
            else if ( item.DataType == FormRecordDataType.DateTime )
            {
                return item.LongVal.Join(',', a => a.HasValue ? a.Value.ToDateTime().ToString("yyyy-MM-dd HH:mm") : string.Empty);
            }
            else
            {
                return item.Vals.Join(',', a =>
                {
                    if ( a.IsNull() )
                    {
                        return string.Empty;
                    }
                    else if ( val.FuncType == DataFuncType.选项值 && val.Items != null )
                    {
                        string[] vals = a.ConvertAll(val.Items.GetValueOrDefault);
                        return string.Join(';', vals);
                    }
                    return a.Join(';');
                });
            }
        }
        public static object FormatValue ( this FormVal val )
        {
            if ( val.IsNull )
            {
                return null;
            }
            else if ( val.DataType == FormRecordDataType.String )
            {
                return val.StrVal;
            }
            else if ( val.DataType == FormRecordDataType.Date )
            {
                return val.LongVal.Value.ToDateTime();
            }
            else if ( val.DataType == FormRecordDataType.DateTime )
            {
                return val.LongVal.Value.ToDateTime();
            }
            else if ( val.DataType == FormRecordDataType.Bool )
            {
                return val.BoolVal.Value;
            }
            else if ( val.DataType == FormRecordDataType.Number )
            {
                return val.NumVal.Value;
            }
            else if ( val.DataType == FormRecordDataType.Array )
            {
                return val.Vals;
            }
            else if ( val.DataType == FormRecordDataType.ListItem )
            {
                return _GetValues(val.ListItem);
            }
            else
            {
                return val.LongVal.Value;
            }
        }
        private static object _GetValues ( FormListItem item )
        {
            if ( item.DataType == FormRecordDataType.Bool )
            {
                return item.BoolVal;
            }
            else if ( item.DataType == FormRecordDataType.String )
            {
                return item.StrVal;
            }
            else if ( item.DataType == FormRecordDataType.Number )
            {
                return item.NumVal;
            }
            else if ( item.DataType == FormRecordDataType.Long || item.DataType == FormRecordDataType.Time )
            {
                return item.LongVal;
            }
            else if ( item.DataType == FormRecordDataType.Date )
            {
                return item.LongVal.ConvertAll<long?, DateTime?>(a => a.HasValue ? a.Value.ToDateTime() : null);
            }
            else if ( item.DataType == FormRecordDataType.DateTime )
            {
                return item.LongVal.ConvertAll<long?, DateTime?>(a => a.HasValue ? a.Value.ToDateTime() : null);
            }
            else
            {
                return item.Vals;
            }
        }
        public static void ToVoidItem ( this FlowAuditLogState log, AuditFlowBody flow, long fromId, long optItemId )
        {
            log.ToVoidRunItem(flow, fromId, optItemId);
            log.CurNodeState.ForEach(( nodeId, state ) =>
            {
                if ( nodeId != fromId )
                {
                    FlowNode node = flow.Nodes[nodeId];
                    if ( node.ParentId.Contains(fromId) )
                    {
                        log.SetNodeState(nodeId, FlowNodeAuditStatus.待开始, optItemId);
                    }
                }
            });
        }
        public static void ToVoidRunItem ( this FlowAuditLogState log, AuditFlowBody flow, long fromId, long? optItemId )
        {
            log.LogItem.ForEach(a =>
            {
                if ( a.Status == FlowAuditItemStatus.审核进行中 || a.Status == FlowAuditItemStatus.待开始 )
                {
                    FlowNode node = flow.Nodes[a.NodeId];
                    if ( node.ParentId.Contains(fromId) )
                    {
                        a.Status = FlowAuditItemStatus.已作废;
                        a.OptItemId = optItemId;
                        if ( a.AuditState == FlowAuditItemStatus.审核通过 )
                        {
                            a.SubFlowState = FlowSubAuditStatus.已作废;
                        }
                    }
                }
            });
        }

        public static bool CheckIsAllowCancel ( this AuditFlowBody flow, FlowNode begin, long[] nodeId )
        {
            if ( begin.ToNodeId.TrueForAll(a => flow.Nodes[a].NodeType == FlowNodeType.结束节点) )
            {
                return false;
            }
            return begin.ToNodeId.TrueForAll(a => _CheckIsCancel(flow, a, nodeId));
        }
        private static bool _CheckIsCancel ( AuditFlowBody flow, long nodeId, long[] endId )
        {
            FlowNode node = flow.Nodes[nodeId];
            if ( endId.Contains(nodeId) || node.NodeType == FlowNodeType.子流程 )
            {
                return node.IsAllowCancel;
            }
            else if ( node.NodeType == FlowNodeType.结束节点 )
            {
                return true;
            }
            else if ( node.IsAllowCancel )
            {
                return node.ToNodeId.TrueForAll(a => _CheckIsCancel(flow, a, endId));
            }
            return false;
        }
        public static SaveAuditBody GetAuditBody ( this FlowAuditLogState log, AuditFlowBody flow )
        {
            SaveAuditBody result = new SaveAuditBody
            {
                Id = log.Id,
                AuditStatus = log.AuditStatus,
                Status = log.Status,
                EndTime = log.EndTime,
                IsChange = log.IsChange,
                ProgressVal = log.ProgressVal,
                PChange = log.ProgChange,
                EndEmpId = log.EndEmpId,
                Adds = new List<AuditLogItemAdd>(),
                NodeState = log.GetNodeState(),
                Updates = new List<AuditLogItemSet>()
            };
            log.LogItem.ForEach(a =>
            {
                if ( a.ChangeType == LogItemChangeType.Add )
                {
                    FlowNode node = flow.Nodes[a.NodeId];
                    result.Adds.Add(new AuditLogItemAdd
                    {
                        BatchNo = node.AuditType == FlowAuditType.多人会审 && a.BatchNo != 0 ? a.BatchNo : null,
                        CompanyId = a.CompanyId,
                        EmpByDeptId = a.EmpByDeptId,
                        EmpByUnitId = a.EmpByUnitId,
                        EmpId = a.EmpId,
                        FlowId = log.FlowId,
                        LogId = log.Id,
                        NodeId = a.NodeId,
                        FormId = node.FormId.GetValueOrDefault(flow.DefFormId.Value),
                        NodeLvl = node.NodeLvl,
                        NodeType = node.NodeType,
                        Status = a.Status,
                        NextDeptId = a.NextDeptId,
                        SubFlowState = a.SubFlowState,
                        AuditState = a.AuditState,
                        MarkState = a.MarkState,
                        OptItemId = a.OptItemId,
                        PrevBackNo = a.PrevBackNo,
                        PrevNodeId = a.PrevNodeId,
                        RootBatchNo = a.RootBatchNo,
                        RootNodeId = a.RootNodeId,
                        TimeOut = a.TimeOut,
                        PrtBatchNo = a.PrtBatchNo,
                        CopyId = a.CopyId,
                        StartTime = a.StartTime
                    });
                }
                else if ( a.ChangeType == LogItemChangeType.Update )
                {
                    result.Updates.Add(new AuditLogItemSet
                    {
                        Id = a.Id,
                        Status = a.Status,
                        SubFlowState = a.SubFlowState,
                        AuditState = a.AuditState,
                        AuditOpinion = a.AuditOpinion,
                        BackNodeId = a.BackNodeId,
                        SignFileId = a.SignFileId,
                        OptItemId = a.OptItemId,
                        EndTime = a.EndTime
                    });
                }
            });
            return result;
        }
        public static void CheckLogState ( this FlowAuditLogState log, AuditFlowBody flow, AfootAuditLogItem item )
        {
            if ( item.RootNodeId == flow.BeginNode )
            {
                if ( log.ProgChange == false )
                {
                    if ( item.AuditState == FlowAuditItemStatus.审核通过 || item.Status == FlowAuditItemStatus.已撤回 )
                    {
                        FlowNode node = flow.Nodes[item.NodeId];
                        if ( node.ProgressVal.HasValue )
                        {
                            log.ProgressVal = node.ProgressVal.Value;
                        }
                    }
                    else if ( item.Status == FlowAuditItemStatus.打回修改 )
                    {
                        log.ProgressVal = 0;
                    }
                    else if ( item.Status == FlowAuditItemStatus.已回退 )
                    {
                        FlowNode node = flow.Nodes[item.BackNodeId.Value];
                        if ( node.ProgressVal.HasValue )
                        {
                            log.ProgressVal = node.ProgressVal.Value;
                        }
                        else
                        {
                            log.ProgressVal = flow.Nodes.Values.Where(c => c.NodeLvl < node.NodeLvl && c.ProgressVal.HasValue).Max(c => c.ProgressVal.Value);
                        }
                    }
                }
                if ( item.Status == FlowAuditItemStatus.审核未通过 && log.LogItem.IsExists(a => a.Status == FlowAuditItemStatus.审核进行中) == false )
                {
                    log.AuditStatus = FlowAuditStatus.审核未通过;
                    log.EndEmpId = item.EmpId;
                }
                else if ( item.Status == FlowAuditItemStatus.终审通过 )
                {
                    log.AuditStatus = FlowAuditStatus.审核通过;
                    log.EndEmpId = item.EmpId;
                }
                else if ( item.Status == FlowAuditItemStatus.已取消 )
                {
                    log.AuditStatus = FlowAuditStatus.已取消;
                    log.EndEmpId = item.EmpId;
                }
                else if ( item.Status == FlowAuditItemStatus.审核通过
                    && log.LogItem.IsExists(c => c.RootNodeId == flow.BeginNode && c.NodeType == FlowNodeType.结束节点)
                    && log.LogItem.IsExists(c => c.Status == FlowAuditItemStatus.审核进行中) == false
                    )
                {
                    log.AuditStatus = FlowAuditStatus.审核通过;
                    log.ProgressVal = 100;
                    log.EndEmpId = item.EmpId;
                }
                else if ( log.AuditStatus == FlowAuditStatus.待提交 )
                {
                    log.AuditStatus = FlowAuditStatus.审核进行中;
                }
            }
            else if ( log.LogItem.IsExists(c => c.RootNodeId == flow.BeginNode && c.Status == FlowAuditItemStatus.审核进行中) == false )
            {
                if ( log.LogItem.IsExists(c => c.RootNodeId == flow.BeginNode && c.Status == FlowAuditItemStatus.审核未通过) )
                {
                    log.AuditStatus = FlowAuditStatus.审核未通过;
                    log.EndEmpId = item.EmpId;
                }
                else if ( log.LogItem.IsExists(c => c.RootNodeId == flow.BeginNode && ( c.Status == FlowAuditItemStatus.终审通过 || c.NodeType == FlowNodeType.结束节点 )) )
                {
                    log.AuditStatus = FlowAuditStatus.审核通过;
                    log.ProgressVal = 100;
                    log.EndEmpId = item.EmpId;
                }
            }
        }

        public static void RefreshNodeState ( this FlowAuditLogState log, AuditFlowBody flow, AfootAuditLogItem item )
        {
            if ( item.RootNodeId == flow.BeginNode )
            {
                return;
            }
            else if ( item.Status != FlowAuditItemStatus.审核通过 && item.Status != FlowAuditItemStatus.审核未通过 && item.Status != FlowAuditItemStatus.终审通过 )
            {
                return;
            }
            _RefreshNodeState(flow, item, log, item.Id);
        }
        private static void _RefreshNodeState ( AuditFlowBody flow, AfootAuditLogItem item, FlowAuditLogState log, long optItemId )
        {
            AfootAuditLogItem root = item.NodeType == FlowNodeType.子流程 ? item : log.LogItem.Find(a => a.NodeId == item.RootNodeId && a.RootBatchNo == item.RootBatchNo);
            FlowNode prevNode = flow.Nodes[root.PrevNodeId.Value];
            AfootAuditLogItem prevItem = log.LogItem.Find(a => a.NodeId == prevNode.Id && a.BatchNo == root.PrevBackNo);
            bool? isPass = _GetSubFlowStatus(prevNode, prevItem, root, log);
            if ( isPass.HasValue == false )
            {
                return;
            }
            else if ( isPass.Value )
            {
                _AuditPass(prevNode, log, prevItem, optItemId);
            }
            else
            {
                _AuditNoPass(flow, log, prevItem, optItemId);
            }
            if ( prevNode.RootNodeId == flow.BeginNode )
            {
                return;
            }
            _RefreshNodeState(flow, prevItem, log, optItemId);
        }
        private static bool? _GetSubFlowStatus ( FlowNode node, AfootAuditLogItem item, AfootAuditLogItem root, FlowAuditLogState log )
        {
            List<AfootAuditLogItem> items = log.LogItem.FindAll(c => c.NodeType == FlowNodeType.子流程 && c.PrevNodeId == node.Id && c.BatchNo == root.BatchNo);
            if ( items.Count == 0 )
            {
                return null;
            }
            KeyValuePair<long, FlowAuditItemStatus>[] status = items.ConvertAllToArray(a => _GetAuditStatus(log, a));
            if ( node.OutNoPassOpt == FlowOutNoPassOptMethod.一票否决 && status.IsExists(c => c.Value == FlowAuditItemStatus.审核未通过) )
            {
                return false;
            }
            else if ( node.OutCondition == FlowOutCondition.子流程全部通过 || node.OutCondition == FlowOutCondition.无 )
            {
                if ( status.IsExists(c => c.Value == FlowAuditItemStatus.审核未通过) )
                {
                    return false;
                }
                return status.IsExists(c => c.Value == FlowAuditItemStatus.审核进行中) ? null : true;
            }
            if ( node.OutCondition == FlowOutCondition.指定子流程通过 && status.IsExists(c => c.Key == node.OutWaitNodeId.Value && c.Value == FlowAuditItemStatus.审核未通过) )
            {
                return false;
            }
            int pass = status.Count(c => c.Value == FlowAuditItemStatus.审核通过);
            int noPass = status.Count(c => c.Value == FlowAuditItemStatus.审核未通过);
            if ( node.OutMinPassNum.HasValue == false || node.OutMinPassNum.Value > status.Length )
            {
                if ( pass == status.Length )
                {
                    return true;
                }
                return noPass != 0 ? false : null;
            }
            if ( pass >= node.OutMinPassNum.Value )
            {
                return true;
            }
            return noPass > ( status.Length - node.OutMinPassNum.Value ) ? false : null;
        }
        private static KeyValuePair<long, FlowAuditItemStatus> _GetAuditStatus ( FlowAuditLogState log, AfootAuditLogItem item )
        {
            IEnumerable<FlowNodeAuditStatus> res = log.LogItem.Where(a => a.RootNodeId == item.NodeId && a.RootBatchNo == item.RootBatchNo)
                .Select(a => a.NodeId).Distinct().Select(a => log.CurNodeState.GetValueOrDefault(a, FlowNodeAuditStatus.待开始));
            if ( res.Contains(FlowNodeAuditStatus.审核进行中) )
            {
                return new KeyValuePair<long, FlowAuditItemStatus>(item.NodeId, FlowAuditItemStatus.审核进行中);
            }
            else if ( res.Contains(FlowNodeAuditStatus.审核未通过) )
            {
                return new KeyValuePair<long, FlowAuditItemStatus>(item.NodeId, FlowAuditItemStatus.审核未通过);
            }
            return new KeyValuePair<long, FlowAuditItemStatus>(item.NodeId, FlowAuditItemStatus.审核通过);
        }


        private static void _AuditNoPass ( AuditFlowBody flow, FlowAuditLogState log, AfootAuditLogItem initiator, long optItemId )
        {
            log.ToVoidRunItem(flow, initiator.NodeId, optItemId);
            initiator.SubFlowState = FlowSubAuditStatus.审核未通过;
            log.SetNodeState(initiator.NodeId, initiator.NodeStatus, optItemId);
        }
        private static void _AuditPass ( FlowNode root, FlowAuditLogState log, AfootAuditLogItem initiator, long optItemId )
        {
            if ( root.OutIsWaitPass )
            {
                log.LogItem.ForEach(c =>
                {
                    if ( c.Status == FlowAuditItemStatus.待开始 && c.PrevBackNo == initiator.BatchNo )
                    {
                        c.AuditState = FlowAuditItemStatus.审核进行中;
                        c.OptItemId = optItemId;
                    }
                });
            }
            initiator.SubFlowState = FlowSubAuditStatus.审核通过;
            initiator.OptItemId = optItemId;
            log.SetNodeState(initiator.NodeId, initiator.NodeStatus, optItemId);
        }
    }
}
